#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
This file is part of SubReader.

SubReader is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

SubReader is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with SubReader.  If not, see <http://www.gnu.org/licenses/>.
"""

#-------------------------------------------#
#             General information           #
#-------------------------------------------#


"""
Description: This project's goal is to display subtitles (.srt and .sub formats)
while a movie is being streamed

Project link: http://code.google.com/p/subreader/

Author: Laurent PABION

Mail: pyzealot/AT/gmail.com
"""

#-------------------------------------------#
#                    TODO                   #
#-------------------------------------------#


"""
! sub support
"""

#-------------------------------------------#
#               Modules used                #
#-------------------------------------------#

import os
import os.path
import re
import sys
import time

#-------------------------------------------#
#          Declaration of constants         #
#-------------------------------------------#

TIME_CHECK_RATE = 1/100.0
DEFAULT_SUB_FRAMERATE = 23.976
SRT_EXT = ".srt"
SUB_EXT = ".sub"
VALID_EXTENSIONS = [SRT_EXT, SUB_EXT]



#-------------------------------------------#
#        Class definition: SubReader        #
#-------------------------------------------#


class SubReader(object):
    """read *.srt + *.sub files and print subtitles to the console"""
    def __init__(self):
        # prompt the user for a filename
        self.filename, self.extension = self.ask_filename()
        # this regular expression will be used to check the input
        # Time pattern = "HH:MM:SS,mmm" e.g. : 01:25:54,125
        self.timePattern = re.compile(r"\d{2}:\d{2}:\d{2},\d{3}")
        self.closedTagPattern = re.compile(r"<[^<]*?/?>")
        
        # prompt for the time elapsed since the film started
        self.timeElapsed = self.ask_time()
        self.now = time.time()
        self.movieStartTime = self.now - self.timeElapsed
        #print "@debug: self.timeElapsed:", self.timeElapsed
        #print "@debug: self.now:", self.now
        #print "@debug: self.movieStartTime:", self.movieStartTime
        
        # open the file and read it
        self.subtitles = self.load_file(self.filename)
        self.nbOfSubtitles = len(self.subtitles)
        self.firstSubtitleTime = self.subtitles[0][1]
        self.lastSubtitleTime = self.subtitles[self.nbOfSubtitles-1][2]
        #print "@debug: first subtitle time: ", self.firstSubtitleTime
        #print "@debug: last subtitle time: ", self.lastSubtitleTime
        #print "@debug: now - first subtitle: ", self.now - (self.firstSubtitleTime)
        #print "@debug: last subtitle - now: ", (self.lastSubtitleTime) - self.now
        #for sub in range (0,10):
        #    print "----------------------------------"
        #    print "sub index:", self.subtitles[sub][0]
        #    print "sub start time:", self.subtitles[sub][1]
        #    print "sub end time:", self.subtitles[sub][2]
        #    print "sub length of display:", self.subtitles[sub][2] - self.subtitles[sub][1]
        #    print "----------------------------------"
        #    print "\n"
        #raw_input("type ENTER")
        #time.sleep(40)

    
    def ask_filename(self):
        """prompt the user for a filename"""
        while True:
            filename = raw_input("Enter the filename: ")
            extension = os.path.splitext(filename)[1]
            if os.path.isfile(filename) and (extension in VALID_EXTENSIONS):
                return filename, extension
            else:
                print "\nWrong input. Please enter a valid *.srt or *.sub filename\n"
        
        
    def ask_time(self):
        """prompt the user for the time to look at"""
        while True:
            movieTime = raw_input("How long since the film started? format = HH:MM:SS,mmm: ")
            if self.timePattern.match(movieTime):
                return self.convert_to_seconds(movieTime)
            else:
                print "\nWrong input. Please enter a valid time (HH:MM:SS,mmm)\n"
                

    def clear_screen(self):
        if os.name == "nt":
            # for Windows NT, XP...
            os.system("cls")
        else:
            # for Linux
            os.system("clear")
    
    def the_end(self):
        """when there is no more subtitles to display"""
        print "\n***No more subtitles to display.***\n"
        raw_input("Hit ENTER to left the program")
        sys.exit(0)
        
    def get_sub_framerate(self):
        # self.framerate = self.get_framerate()
        pass
        
    def initial_display(self):
        """look for the first subtitle to display"""

        self.clear_screen()
        # case 1 : no subtitle till now
        if time.time() < self.firstSubtitleTime:
           
           # pause till the first subtitle start time is reached
           time.sleep(self.firstSubtitleTime - time.time())
           self.timeElapsed = self.timeElapsed + (self.firstSubtitleTime - self.timeElapsed)
           

        # case 2 : at least one subtitle has been displayed
        for element in self.subtitles:
            #print "@debug: element[1] <= self.timeElapsed <= element[2]", element[1], "<=", self.timeElapsed, "<=", element[2]
            #time.sleep(1)
            # looking for the correct subtitle to display.
            
            if time.time() > element[2]:
                # there is no more subtitles to display
                if time.time() > self.lastSubtitleTime:
                    self.the_end()
                else:
                    continue
            
            # in between two subtitles
            elif time.time() <= element[2] and time.time() < element[1]:
                time.sleep(element[1] - time.time())
                #self.timeElapsed = self.timeElapsed + (element[1] - self.timeElapsed)
                for line in element[3]:
                    print line
            
            # right subtitle found => printed to the screen
            else:
               for line in element[3]:
                    print line
                    
            #print "@debug element[0]: ", str(element[0])
            #print "@debug element[2] - self.timeElapsed: ", str(element[2] - self.timeElapsed)
            # return the index of the subtitle to display + the number of seconds it must be displayed
            return (element[0], element[2] - time.time())
            
    def queued_display(self, indexInitialSubtitle):
        """cycle through the remaining subtitles"""
        
        # index starts at zero, not one
        indexPrevSubtitle = (indexInitialSubtitle - 1)
        indexNextSubtitle = indexPrevSubtitle + 1
        nbSubtitlesLeft = len(self.subtitles) - indexPrevSubtitle
        
        #print "@debug: indexPrevSubtitle=", str(indexPrevSubtitle)
        #print "@debug: indexNextSubtitle=", str(indexNextSubtitle)
        #time.sleep(10)
        
        # display subtitles until the last one
        while nbSubtitlesLeft > 1:
            
            # pause delay between two subtitles = [start time of next subtitle] - [end time of previous subtitle]
            # clear the screen until the next subtitle is displayed
            self.clear_screen()
            delay = self.subtitles[indexNextSubtitle][1] - time.time()
            #print "delay till the next subtitle: ", delay
            if delay > 0:
                time.sleep(delay)
            
            # print the text of the current subtitle
            for line in self.subtitles[indexNextSubtitle][3]:
                print line
            
            # calculate the number of seconds the subtitle will be printed to the screen 
            displayTime = self.subtitles[indexNextSubtitle][2] - time.time()
            #print "display time of this subtitle: ", displayTime
            time.sleep(displayTime)
            
            # recalculate variables before the next loop
            indexPrevSubtitle = indexNextSubtitle
            indexNextSubtitle = indexNextSubtitle + 1
            nbSubtitlesLeft = nbSubtitlesLeft - 1
        
        
    def load_file(self, fileToRead):
        """read subtitles from the file"""
        try:
            FILE = open(fileToRead,"r")
        except:
            print "\nThe file cannot be read...\n"
            raw_input("Hit ENTER to quit")
            sys.exit(0)
 
        # read a file according to its extension
        if self.extension == SRT_EXT:
            subtitles = self.srt_reader(FILE)
         
        else:
            subtitles = self.sub_reader(FILE)
            
        FILE.close()

        return subtitles
        
    def show(self):
        """print subtitles to the console"""
        # look for the first subtitle, print it and return some info about it
        self.initial_info = self.initial_display()
        # pause before displaying the next subtitle
        print "time to wait: ", self.initial_info[1]
        time.sleep(self.initial_info[1])
        # cycle through the remaining subtitles and display them
        self.queued_display(self.initial_info[0])
        # there is no more subtitles to display
        self.the_end()
        
    def srt_reader(self, fileObject):
        """read and parse *.srt files
        format specification :
        [1] incremental count of subtitles (starts with 1)
        [2] [start timecode] [-->] [end timecode] [display coordinates]
        [3] text of the subtitle 
        [...] another line of text
        [...+1] blank line
        """
        print "@debug: srt_reader in action"
        subtitle = []
        convertedSubtitle = []
        subtitles = []
        
        for line in fileObject.readlines():
            # there is a blank line between each subtitle (see *.srt format specification)
            if line != "\n":
                subtitle.append(line)
            
            else:
                # now that we have a complete  subtitle we convert it to a fixed format
                convertedSubtitle = self.convert_srt_subtitle(subtitle)

                # the converted subtitle is appended to another list that will store all the subtitles
                subtitles.append(convertedSubtitle)
            
                # the subtitle list is cleared before going back to the beginning of the loop
                del subtitle[:]

        return subtitles
            
    def convert_srt_subtitle(self, subtitle):
        """convert an srt subtitle to the following format:
           convertedSubtitle = list(a,b,c,d)
           where a=subtitle number, b=start time, c=end time, d=text of the subtitle
        """
        convertedSubtitle = [None]*4
        
        NumberOfElements = len(subtitle)
        
        # subtitle number = string converted to an integer
        convertedSubtitle[0] = int(subtitle[0].replace("\n",""))
        
        # start time and end time
        convertedSubtitle[1], convertedSubtitle[2] = self.parse_srt_time(subtitle[1])
        #print "@debug: convertedSubtitle[1]: ", convertedSubtitle[1], "convertedSubtitle[2]: ", convertedSubtitle[2]
        
        # text of the subtitle
        tmp = []
        for line in range(2, NumberOfElements):
            # strip tags if any
            strippedLine = self.closedTagPattern.sub("",subtitle[line])
            # remove the "\n" at the end of the line
            tmp.append(strippedLine.replace("\n",""))
        convertedSubtitle[3] = tmp

        return convertedSubtitle
    
    def parse_srt_time(self, srtStringTime):
        """return a list with the start time and the end time converted to seconds"""
        timecodes = [None]*2
        
        # regex used to extract only the timecodes. Coordinates are excluded (see *.srt format specification)
        timecodes = self.timePattern.findall(srtStringTime)
        
        # each timecode is converted to seconds and the movie start time is added
        for index, timecode in enumerate(timecodes):
            timecodes[index] = self.convert_to_seconds(timecode) + self.movieStartTime

        return timecodes
        
    def sub_reader(self, fileObject):
        """read and parse *.srt files"""
        print "@debug: sub_reader in action"

    def convert_to_seconds(self, strTime):
        """convert the time string to seconds
        time string format : HH:MM:SS,mmm
        """
        movieTime = strTime.split(":")
        hours = float(movieTime[0])
        minutes = float(movieTime[1])
        seconds = float(movieTime[2].replace(",","."))
        return (hours * 60 * 60) + (minutes * 60) + (seconds)
    
    
#-------------------------------------------#
#                  Main()                   #
#-------------------------------------------#

if __name__ == "__main__":
    subtitles = SubReader()
    subtitles.show()